package com.easyOrder.web.action.requisition;

import com.easyOrder.core.comm.BaseAction;
import com.easyOrder.core.context.ApiMethodAttribute;
import com.easyOrder.core.exception.api.InvalidOprationException;
import com.easyOrder.core.mq.ISender;
import com.easyOrder.core.mq.Topic;
import com.easyOrder.core.mq.TopicTag;
import com.easyOrder.core.utils.WebUtils;
import com.easyOrder.model.Branch;
import com.easyOrder.model.Requisition;
import com.easyOrder.model.RequisitionDetail;
import com.easyOrder.param.requisition.RequisitionOrderParam;
import com.easyOrder.param.requisition.RequisitionParam;
import com.easyOrder.service.branch.BranchService;
import com.easyOrder.service.enums.BranchState;
import com.easyOrder.service.enums.RequisitionState;
import com.easyOrder.service.material.MaterialService;
import com.easyOrder.service.requisition.RequisitionDetailService;
import com.easyOrder.service.requisition.RequisitionService;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.gson.Gson;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;
import java.text.MessageFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import static com.google.common.base.Preconditions.checkArgument;

/**
 * Created by liutao on 2017/7/19.
 */
@RestController
@RequestMapping("/requisition")
@ApiMethodAttribute(nonSignatureValidation = false, nonSessionValidation = true)
public class RequisitionAction extends BaseAction {

    @Autowired
    private BranchService branchService;

    @Autowired
    private ISender sender;

    @Autowired
    private MaterialService materialService;

    @Autowired
    private RequisitionDetailService requisitionDetailService;
    @Autowired
    private RequisitionService requisitionService;


    @Autowired
    private RedisTemplate<String, Boolean> springRedisTemplate;

    private static final Logger logger = Logger.getLogger(RequisitionAction.class);

    /**
     * 添加订单
     *
     * @param requisition
     * @return
     */
    @RequestMapping(value = "/add", method = {RequestMethod.POST, RequestMethod.OPTIONS})
    public Object add(@RequestBody RequisitionParam requisition) {
        String key = "requisition_" + requisition.getTag() + "-" + requisition.getBranchId();
        checkArgument(null != requisition.getTag() && requisition.getBranchId() != null, "二维码失效");
        checkArgument(CollectionUtils.isNotEmpty(requisition.getItems()), "明细不能为空");
        Branch branch = branchService.findById(requisition.getBranchId());
        checkArgument(branch != null && branch.getStatusId() == BranchState.normal.getValue(), "二维码失效");
        if (springRedisTemplate.hasKey(key)) {
            throw new InvalidOprationException("下单信息已提交, 系统正在处理中, 请稍候...");
        } else {
            springRedisTemplate.opsForValue().set(key, Boolean.TRUE, TimeUnit.HOURS.toSeconds(1), TimeUnit.SECONDS);
        }
        requisition.setTenantId(branch.getTenantId());
        requisition.setBranchName(branch.getName());
        Set<Long> materialIds = Sets.newHashSet();
        Map<Long, BigDecimal> map = Maps.newHashMap();
        validationRequisitionItems(requisition, materialIds, map);
        materialService.checkInvalidMaterials(materialIds, map);
        String messageId = pushRequisitionCreateMessage(requisition);


        return wrapperJsonView(messageId);
    }

    /**
     * 发送创建订单消息队列
     *
     * @param requisition
     * @return
     */
    private String pushRequisitionCreateMessage(RequisitionParam requisition) {
        Topic topic = getTopUsed();
        Gson gson = new Gson();
        String messageBody = gson.toJson(requisition, RequisitionParam.class);
        if (logger.isDebugEnabled()) {
            logger.debug(MessageFormat.format("Prepare send {0} to {1}", messageBody, topic.getName()));
        }
        String messageId = sender.sendMessage(topic.getName(), messageBody,
                TopicTag.requisitionCreate.name());
        return messageId;
    }

    /**
     * 验证订单明细商品
     *
     * @param requisition
     * @param materialIds
     * @param map
     */
    private void validationRequisitionItems(@RequestBody RequisitionParam requisition, Set<Long> materialIds, Map<Long, BigDecimal> map) {
        requisition.getItems().forEach(
                item -> {
                    checkArgument(
                            null != item.getMaterialId(),
                            MessageFormat.format("明细商品ID不能为空",
                                    item.getMaterialId()));
                    checkArgument(
                            null != item.getQuantity(),
                            MessageFormat.format("申购商品ID: {0}的申购数量不能为空",
                                    item.getMaterialId()));
                    checkArgument(item.getQuantity().compareTo(new BigDecimal(10000000)) == -1, "购买数量超出可支持的范围");
                    materialIds.add(item.getMaterialId());
                    map.put(item.getMaterialId(), item.getQuantity());
                    if (StringUtils.isNotBlank(item.getNote())) {
                        item.setNote(item.getNote().replaceAll("\\p{So}+", ""));
                    }
                });
    }


    /**
     * 下单
     *
     * @param param
     * @return
     */
    @RequestMapping(value = "/pay", method = {RequestMethod.POST, RequestMethod.OPTIONS})
    public Object payOrder(@RequestBody RequisitionOrderParam param) {
        checkArgument(param.getRequisitionId() != null, "订单ID不能为空");
        String key = "pay_order_" + param.getRequisitionId();
        logger.warn("key:" + key);
        if (springRedisTemplate.hasKey(key)) {
            throw new InvalidOprationException("系统正在处理中, 请稍候...");
        } else {
            springRedisTemplate.opsForValue().set(key, Boolean.TRUE, TimeUnit.HOURS.toSeconds(1), TimeUnit.SECONDS);
        }
        List<RequisitionDetail> requisitionDetails = requisitionDetailService.findOrder(param.getRequisitionId());
        checkArgument(CollectionUtils.isNotEmpty(requisitionDetails), "订单ID不存在");
        Set<Long> materialIds = Sets.newHashSet();
        Map<Long, BigDecimal> map = Maps.newHashMap();
        requisitionDetails.forEach(item -> {
            materialIds.add(item.getMaterialId());
            map.put(item.getMaterialId(), item.getQuantity());
        });
        materialService.checkInvalidMaterials(materialIds, map);
        param.setSession(WebUtils.Session.get());

        return wrapperJsonView(pushRequisitionOrderMessage(param));
    }

    /**
     * 发送下单消息队列
     *
     * @param param
     * @return
     */
    private String pushRequisitionOrderMessage(RequisitionOrderParam param) {
        Topic topic = getTopUsed();
        String messageBody = new Gson().toJson(param, RequisitionOrderParam.class);
        if (logger.isDebugEnabled()) {
            logger.debug(MessageFormat.format("Prepare send {0} to {1}", messageBody, topic.getName()));
        }
        String messageId = sender.sendMessage(topic.getName(), messageBody,
                TopicTag.requisitionOrder.name());
        return messageId;
    }


    /**
     * 取消订单
     *
     * @return
     */
    @RequestMapping(value = "/cancel", method = {RequestMethod.GET, RequestMethod.OPTIONS})
    public Object cancelOrder(@RequestParam Long requisitionId) {
        Requisition requisition = requisitionService.findById(requisitionId);
        checkArgument(requisition != null, "订单ID不存在");
        checkArgument(requisition.getStatusId() == RequisitionState.order.getValue(), RequisitionState.parse(requisition.getStatusId()).getDesc() + "的订单不能取消");
        requisitionService.cancelOrder(requisitionId);
        Requisition r = requisitionService.findById(requisitionId);
        String key = "requisition_" + r.getTag() + "-" + r.getBranchId();
        if (springRedisTemplate.hasKey(key)) {
            springRedisTemplate.delete(key);
        }
        return wrapperJsonView(key);
    }

    /**
     * 客户完成订单
     * @return
     */
    @RequestMapping(value = "/complete", method = {RequestMethod.GET, RequestMethod.OPTIONS})
    public Object completeOrder(@RequestParam Long requisitionId){
        Requisition requisition = requisitionService.findById(requisitionId);
        checkArgument(requisition != null, "订单ID不存在");
        checkArgument(requisition.getStatusId() == RequisitionState.completed.getValue()||requisition.getStatusId() == RequisitionState.receiving.getValue(),  "商家未全部接单，订单不能完成");
        requisitionService.completeOrder(requisitionId);
        return wrapperJsonView(new Date());
    }

    @RequestMapping(value = "/payed/cancel", method = {RequestMethod.GET, RequestMethod.OPTIONS})
    public Object cancelPayedOrder(@RequestParam Long requisitionId){
        Requisition requisition = requisitionService.findById(requisitionId);
        checkArgument(requisition != null, "订单ID不存在");
        checkArgument(requisition.getStatusId() == RequisitionState.order.getValue(), RequisitionState.parse(requisition.getStatusId()).getDesc() + "的订单不能取消");
        requisitionService.cancelOrder(requisitionId);
        return wrapperJsonView(new Date());
    }



}
